﻿using System;
using System.Collections.Generic;
using SobrietyEngine.Common;
using SobrietyEngine.Components;
using SobrietyEngine.Logging;

namespace SobrietyEngine.Actor
{
    public class ActorDefinitionReader
    {        
        public static Dictionary<String, ActorTemplate> Load(String data)
        {
            //for our tmeplates
            Dictionary<String, ActorTemplate> templates = new Dictionary<string, ActorTemplate>();

            //runs through the UDMF formated text and loads all items
            StringData sd = StringData.ReadData(ref data);
            
            //for parsing our data
            List<String> namespaces = new List<string>();

            //lets iterate through each item in the stringdata we just loaded form the UDMF file
            foreach (StringData sdat in sd.SubTokens)
            {
                String token = sdat.Token;
                Dictionary<string, string> kvps = sdat.Data;

                //get our list of namespaces
                if (token == "namespaces")
                {
                    foreach (String name in sdat.Data.Values)
                        namespaces.Add(name);
                }
                //create our actorDefinition, check components for correctness
                else if (token == "actor")
                {
                    ActorTemplate at = new ActorTemplate();
                    if (!sdat.Data.ContainsKey("name"))
                        Logger.Error("Error loading actor definition, missing data field 'name'");

                    at.Name = sdat.Data["name"];
                    at.InheritedFrom = String.Empty;
                    if(sdat.Data.ContainsKey("from"))
                        at.InheritedFrom = sdat.Data["from"];

                    //if we have inherited from an actor, copy its components and component data
                    if (at.InheritedFrom != String.Empty)
                    {
                        foreach (String compName in templates[at.InheritedFrom].Components.Keys)
                            at.Components.Add(compName, templates[at.InheritedFrom].Components[compName]);
                    }

                    //go through subtokens (component data) and add to actorDefinition
                    //overwriting anything that may already exist
                    foreach (StringData compData in sdat.SubTokens)
                    {
                        //check if component exists in our factory
                        Boolean found = false;
                        if (!ComponentFactory.DoesExist(compData.Token))
                        {
                            //try with our various namespaces
                            foreach (String nameSpace in namespaces)
                            {
                                if (ComponentFactory.DoesExist(nameSpace + "." + compData.Token))
                                {
                                    compData.Token = nameSpace + "." + compData.Token;
                                    found = true;
                                    break;
                                }
                            }
                        }
                        if (found == false)
                        {
                            //lets try some tricks to locate this. get just the class name
                            //and see if we have any components o this class name, then convert to the strType
                            String className = compData.Token;
                            if(compData.Token.LastIndexOf('.') != -1)
                                className = compData.Token.Substring(compData.Token.LastIndexOf('.') + 1);

                            String typeName = ComponentFactory.TypeStringFromClassName(className);
                            if (typeName != String.Empty)                            
                                compData.Token = typeName;
                            else                            
                                Logging.Logger.GetSingleton().WriteError("ActorTemplateParser::parse: " + compData.Token + " not found in registry");
                        }

                        //add the component
                        if (at.Components.ContainsKey(compData.Token))
                            //we have inherited stuff, so merge the parameters together
                            at.Components[compData.Token].Merge(new Parameters(compData.Data), true);
                        else
                            //add the component and data
                            at.Components.Add(compData.Token, new Parameters(compData.Data));
                    }                    

                    //add thw actorDefinition to the tempaltes dictionary
                    if (templates.ContainsKey(at.Name))
                        Logging.Logger.Error("Actor Template Parsing: Actor already exist in library! Are you loading the template twice? actor name: " + at.Name);
                    else
                        templates.Add(at.Name, at);
                }
            }

            return templates;
        }        
    }
}